package main

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"time"
)

type tree struct {
	n     int
	x     int
	y     int
	right  *tree
	diagUp  *tree
	down *tree
	diagDown *tree
}

func main() {
	start := time.Now()
	array := readNumber("./grid.txt")
	tree := createTree(array)
	tree = createDiags(tree)
	printTree(tree)
	printDiag(tree)
	//printTree(tree.down)
	newArray := createArray(array)
	create2d(newArray)
	stop := time.Now()
	fmt.Println("Execution time:", stop.Sub(start))
}

func create2d(array []int) [][]int {
	array2 := make([][]int, 20)
	for i := 0; i < 20; i++ {
		array2[i] = make([]int, 20)
	}
	a := 0
	b := 0
	for i := 0; i < len(array); i++ {
		if a == 20 {
			a = 0
			b++
			i--
		} else {
			array2[a][b] = array[i]
			fmt.Printf("put %v at %v,%v\n", i, a, b)
			a++
		}
	}
	fmt.Println(array2)
	return array2
}

func createArray(array []int) []int {
	array2 := make([]int, 400)
	k := 0
	for i := 0; i < len(array); i += 2 {
		a := array[i]
		b := array[i+1]
		a *= 10
		n := a + b
		array2[k] = n
		k++
	}
	return array2
}

func createTree(array []int) *tree {
	x := 1
	y := 1
	//array2 := make([]int, 400)
	a := array[0]
	b := array[1]
	a *= 10
	n := a + b
	root := &tree{n, x, y, nil, nil, nil, nil}
	currentNode := root
	x++
	for i := 2; i < len(array); i += 2 {
		a := array[i]
		b := array[i+1]
		a *= 10
		n := a + b
		if x != 21 {
			newNode := &tree{n, x, y, nil, nil, nil, nil}
			currentNode.right = newNode
			currentNode = newNode
			x++
		} else {
			x = 1
			y++
			newNode := &tree{n, x, y, nil, nil, nil, nil}
			currentNode = getNodeDown(root, y-2)
			currentNode.down = newNode
			currentNode = newNode
			x++
		}
	}
	return root

}

func createDiags(root *tree) *tree {
	cur := root
	down := root.down
	var up *tree = nil
	k := 0
	for cur != nil {
		for cur != nil {
			if up != nil {
				cur.diagUp = up.right
			} else {
				cur.diagUp = nil
			}
			if down != nil {
				cur.diagDown = down.right
			} else {
				cur.diagDown = nil
			}
			up = cur
			if cur.down != nil {
				cur = cur.down
				down = cur.down
			} else {
				cur = nil
				down = nil
			}
		}
		k++
		print(k)
		cur = getNodeRight(root, k)
	}
	return root
}

func getNodeDown(root *tree, down int) *tree {
	cur := root
	if down > 0 {
		for i := 0; i < down; i++ {
			cur = cur.down
		}
	}
	return cur
}

func getNodeRight(root *tree, right int) *tree {
	cur := root
	if right > 0 {
		for i := 0; i < right; i++ {
			cur = cur.right
		}
	}
	return cur
}

func printTree(root *tree) {
	cur := root
	k := 0
	for cur != nil {
		for cur != nil {
			fmt.Printf("[%v]%v,%v->", cur.n, cur.x, cur.y) 
			cur = cur.right
		}
		fmt.Println("nil\n")
		k++
		cur = getNodeDown(root, k)
	}
}

func printDiag(root *tree) {
	cur := root
	for cur != nil {
		fmt.Printf("[%v]%v,%v->", cur.n, cur.x, cur.y) 
		cur = cur.diagDown
	}
	fmt.Println("nil\n")
}

//Reads the file and returns only the actual numbers in a slice of ints
func readNumber(filename string) []int {
	n := 0
	bigNumber := make([]byte, 800)
	big := make([]int, 800)
	//Automatically reads the whole file and returns an array of bytes
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	//We get rid of any byte that is not a number (like '\n')
	//so we keep only the actual numbers. Those are the bytes 48 to 57
	//48 is number 0 and 57 is number 9.
	for k := 0; k < len(buf); k++ {
		if int(buf[k]) >= 48 && int(buf[k]) <= 57 {
			bigNumber[n] = buf[k]
			n++
		}
	}
	//We convert the bytes to ints so we can make calculations
	for i := 0; i < len(bigNumber); i++ {
		big[i], _ = strconv.Atoi(string(bigNumber[i]))
	}
	return big
}
